The functions used with PIO maps are summarized in Table 14-1.
A kernel-level device driver creates a PIO map by calling pio_mapalloc(). This function performs memory allocation and so can sleep. PIO maps are typically created in the pfxedtinit() entry point, where the driver first learns about the device addresses from the contents of the edt_t structure (see "Entry Point edtinit()").
The parameters to pio_mapalloc() describe the range of addresses that can be mapped in terms of
A call to pio_mapfree() releases a PIO map. PIO maps created by a loadable driver must be released in the pfxunload() entry point (see "Entry Point unload()" and "Unloading").
The pio_badaddr() and pio_badaddr_val() functions test the mapped address to see if it is usable for input. Both functions perform the same operation: operating through a PIO map, they test a specified bus address for validity by reading 1, 2, 4, or 8 bytes from it. The pio_badaddr_val() function returns the value that it reads while making the test. This can simplify coding, as shown in Example 14-1.
Example 14-1 : Comparing pio_badaddr() to pio_badaddr_val()
unsigned int gotvalue; piomap_t *themap; /* Using only pio_badaddr() */ if (!pio_badaddr(themap,CTLREG,4) { (void) pio_bcopyin(themap,CTLREG,&gotvalue,4,4,0); ...use "gotvalue" /* Using pio_badaddr_val() */ if (!pio_badaddr_val(themap,CTLREG,4,&gotvalue)) { ...use "gotvalue"The pio_wbadaddr() function tests a mapped device address for writeability. The pio_wbadaddr_val() not only tests the address but takes a specific value to write to that address in the course of testing it.
You can use this address to load or store data into device registers. In the pfxmap() entry point (see "Concepts and Use of mmap()"), you can use this address with the v_mapphys() function to map the range of device addresses into the address space of a user process.
You cannot extract a kernel address from an unfixed PIO map, as explained under "Unfixed PIO Maps".
The series of functions pio_andb_rmw() and pio_orb_rmw() perform a read-modify-write cycle on the VME bus. You can use them to set or clear bits in device registers. A read-modify-write cycle is faster than a load followed by a store since it uses fewer system bus cycles.
The Challenge and Onyx architecture provides for a total of 15 separate, 8 MB windows on VME address space for each VME bus. Two of these are permanently reserved to the kernel, and one window is reserved for use with unfixed mappings. The remaining 12 windows are available to implement fixed PIO maps.
When the kernel creates a fixed PIO map, the map is associated with one of the 12 available VME mapping windows. The kernel tries to be clever, so that whenever a PIO map falls within an 8 MB window that already exists, the PIO map uses that window. If the desired VME address is not covered by an open window, one of the twelve windows for that bus is opened to expose a mapping for that address.
It is possible in principle to configure thirteen devices that are scattered so widely in the A32 address space that twelve, 8 MB windows cannot cover all of them. In that unlikely case, the attempt to create the thirteenth fixed PIO map will fail for lack of a mapping window.
In order to prevent this, simply configure your PIO addresses into a span of at most 96 MB per bus (see "Configuring Device Addresses").
You can use an unfixed map with kernel functions that copy data or perform read-modify-write cycles. These functions use the one mapping window that is reserved for unfixed maps, repositioning it in VME space if necessary.
The lboot command uses an unfixed map to perform the probe and exprobe sequences from VECTOR statements (see "Configuring the System Files"). As a result, these probes do not tie up mapping windows.